package taweb.flex.air.fexBrowser.util
{
	import mx.collections.ArrayCollection;
	import mx.utils.URLUtil;
	
	import taweb.flex.air.fexBrowser.struct.URLNode;

	/**
	 * Le parseur de la page.
	 */
	public class Parser
	{
		
		/**
		 * L'URL de la page chargée.
		 */
		private var currentUrl : String;
		
		/**
		 * Le constructeur.
		 * @param url L'URL de la page à traiter.
		 */		
		public function Parser(url:String)
		{
			this.currentUrl = unescape(url);
		}
		
		/**
		 * La méthode de déclenchement de parse.
		 * @param requestResult Le résultat de la requête URL (contenu de la page; XHTML).
		 * @param format Le format du résultat (e4x ou text).
		 */		
		public function run(requestResult:Object, format:String):void
		{
			var links:Array;
			
			// On extrait les liens en respectant le format (X)HTML
			if(format=="e4x")
			{
				links = extractXHTMLlinks(requestResult);
			}
			else // text
			{
				links = extractHTMLlinks(requestResult);
			}
			
			// On structure les liens (noeuds)
			structLinks(links);
		}
		
		/**
		 * Caste un objet XHTML en object XML.
		 */
		private function objectToXML(XMLsrc:Object):XML
		{
			// La configuration de format XML dont on veut caster l'objet XHTML
			XML.ignoreWhitespace = false;
			XML.prettyPrinting = false;
			default xml namespace = new Namespace("http://www.w3.org/1999/xhtml");
			
			// Le caste
			return XMLsrc as XML;
		}
		
		/**
		 * Extrait tous les liens de la page XHTML
		 */
		private function extractXHTMLlinks(requestResult:Object):Array
		{
			trace("extractXHTMLLinks begin..");
			var linksResult : Array = new Array();
			
			// On caste le resultat XHTML dans un objet XML
			var resultXML:XML = objectToXML(requestResult);
			
			// Extraction des liens (balises: <a href="..."> )
			var xmlLinks : XMLList = resultXML..a.(hasOwnProperty("@href"));
			
			var href : String;
			var fullURLLink : String;
			var labelLink : String;
			var xmlLinkImages : XMLList;
			
			// On ajoute un couplet label=URL vers la page courante
			linksResult.push(new KeyVal("Index", currentUrl));
			
			// Pour chaque lien de la page
			for each (var xmlLink : XML in xmlLinks)
			{
				// On récupère le chemin
				href = unescape(xmlLink..@href);
				
				// On traite les chemins relatifs ou absolues avec les protocoles supportés (http/s & file)
				if(FexURLUtil.isURL(href) || URLUtil.getProtocol(href)=="")
				{
					fullURLLink = FexURLUtil.getFullURL(currentUrl, href);
					
					// Si le contenu de lien est de texte on le récupère comme label
					if(xmlLink.hasSimpleContent())
					{
						labelLink = xmlLink.toString();
					}
					else
					{
						// Sinon, on récupère la valeur de l'attribut "alt" de la première image
						xmlLinkImages = xmlLink..img.(hasOwnProperty("@alt") && hasOwnProperty("@src"));
						if(xmlLinkImages.length()==1)
						{
							labelLink = xmlLinkImages[0]..@alt;
							
							// Si l'attribut "alt" n'est pas rensigné, 
							// on prends la valeur de l'attribut "src"
							if(labelLink=="")
							{
								labelLink = FexURLUtil.getFullURL(currentUrl, xmlLinkImages[0]..@src);
							}
						}
						
						if(labelLink=="")
						{
							labelLink = "Page";
						}
					}
					
					trace("Link : " + fullURLLink + " ; Label : " + labelLink);
					
					// On ajoute un couplet label=URL dans la liste des liens extraits
					linksResult.push(new KeyVal(labelLink, fullURLLink));
				}
			}
			
			trace("extractXHTMLLinks end.");
			
			return linksResult;
		}
		
		/**
		 * Extrait tous les liens de la page HTML
		 */
		private function extractHTMLlinks(requestResult:Object):Array
		{
			trace("extractHTMLLinks begin..");
			
			var linksResult : Array = new Array();
			
			// On supprime les retours à la ligne
			var nlExpr:RegExp = new RegExp('\n',"g");
			var htmlsrc:String = requestResult.replace(nlExpr, "")
			
			// On extrait toutes la balises <a href="">...</a>
			var patternLink:RegExp = new RegExp('<a[^>]*href="(.*?)<\/a>', "gi");
			var ATags:Array = htmlsrc.match(patternLink);
			
			var fullURLLink : String;
			var labelLink : String;
			
			var href:String;
			var innerValue:String;
			
			var posHrefBegin:int;
			var posHrefEnd:int;
			
			var posInnerValueBegin:int;
			var posInnerValueEnd:int;
			
			// On ajoute un couplet label=URL vers la page courante
			linksResult.push(new KeyVal("Index", currentUrl));
			
			// Pour chaque tag
			for each(var linkTxt:String in ATags)
			{
				// Href
				posHrefBegin = linkTxt.indexOf("href=\"") + 6;
				posHrefEnd = linkTxt.indexOf("\"", posHrefBegin);
				href = linkTxt.substring(posHrefBegin,  posHrefEnd);
				
				// Inner value (label)
				posInnerValueBegin = linkTxt.indexOf(">") + 1;
				posInnerValueEnd = linkTxt.lastIndexOf("<");
				innerValue = Tools.trim(linkTxt.substring(posInnerValueBegin,  posInnerValueEnd));
				
				// On traite les chemins relatifs ou absolues avec les protocoles supportés (http/s & file)
				if(FexURLUtil.isURL(href) || URLUtil.getProtocol(href)=="")
				{
					fullURLLink = FexURLUtil.getFullURL(currentUrl, href);
					
					if(Tools.isSimpleContent(innerValue))
					{
						labelLink = innerValue;
					}
					else
					{
						var images:Array = Tools.extractTag(innerValue, "img");
						if(images.length == 1)
						{
							labelLink = Tools.getAttributeValue(images[0], "alt");
							
							if(labelLink == "")
							{
								labelLink = FexURLUtil.getFullURL(currentUrl, Tools.getAttributeValue(images[0], "src"));
							}
						}
						
						if(labelLink=="")
						{
							labelLink = "Page";
						}
					}
					
					trace("Link : " + fullURLLink + " ; Label : " + labelLink);
					
					// On ajoute un couplet label=URL dans la liste des liens extraits
					linksResult.push(new KeyVal(labelLink, fullURLLink));
				}
				
			}
			
			trace("extractHTMLLinks end.");
			
			return linksResult;
		}
		
		/**
		 * Structure les liens extraits.
		 */
		private function structLinks(links : Array):void
		{
			trace("structLinks begin..");
			
			// On intégre chaque lien dans la structure des noeuds
			for each (var link:KeyVal in links)
			{
				trace("URL : " + link.getVal);
				
				// On passe toujours par le même noeud (Singleton)
				URLNode.Instance.addPath(link.getVal, link);
			}
			
			trace("structLinks end.");
		}
		
	}
}